//******************************************************************************
//  Lab 7 - Dice
//
//  Description:
//
//	"Write a dice roller C program that waits for a switch to be pressed and then
//	 displays two dice which randomly change values. The dice roll begins rapidly
//	 and progressively slows down until it stops (after approximately 3-5
//	 seconds). A congratulatory ditty is played when doubles are rolled. If
//	 doubles are rolled twice in a row, output a raspberry tone. Write an
//	 assembly language function which returns a random number from 1 to 6 and
//	 call this function from your C program." 
//
//   Author:	Paul Roper, Brigham Young University
//				March 2010
//
//   Built with Code Composer Essentials Version: 3.2
//*******************************************************************************
//
//      A  P4.4     Left Pot  O--O  O  Servo #1
//      B  P4.5       Buzzer  O--O  O  Servo #2
//      C  P4.6   Thermistor  O  O--O  LED_4
//      D  P2.2  ADXL345 INT  O  O--O  SW_3
//      E  P2.3         SW_4  O--O  O  Servo #3 
//      F  P2.4    Backlight  O--O  O  Servo #4
//      G  P4.3    Right Pot  O--O  O  EZ0_AN
//      H  P2.1         SW_2  O--O  O  EZ0_TX
//
//	                   MSP430F2274
//                    -----------------
//                /|\|         XIN P2.6|-->LED_D
//                 | |        XOUT P2.7|-->LED_C
//                 --|RST              |
//                   |     P3.0/UCB0STE|
//                   |     P3.1/UCB0SDA|<-|---+->|P3.1/UCB0SDA  XIN|-
//                   |     P3.2/UCB0SCL|<-+----->|P3.2/UCB0SCL     |
//                   |     P3.3/UCB0CLK|
//                   |                 |
//         RED LED-->|P1.0         P2.0|<--SW1 (pull-up)
//       GREEN LED-->|P1.1         P2.1|<--SW2 (pull-up)
//    eZ430 BUTTON-->|P1.2         P2.2|<--SW3 (pull-up)
//                   |             P2.3|<--SW4 (pull-up)
//                   |             P2.4|-->LCD BACKLIGHT
//                   |             P3.3|-->LED_B
//                   |             P4.3|-->LEFT POTENTIOMETER
//                   |             P4.6|-->LED_A
//                   |                 |
//                   |             P4.5|-->BUZZER
//
//******************************************************************************
//
#include <stdio.h>
#include <math.h>
#include "msp430x22x4.h"
#include "stdlib.h"
#include "eZ430X.h"
#include "lcd.h"
#include "dice.h"


//-----------------------------------------------------------
//	external references
extern void drawDieFrame(int column);
extern void outDie0(int column);
extern void outDie1(int column);
extern void outDie2(int column);
extern void outDie3(int column);
extern void outDie4(int column);
extern void outDie5(int column);
extern void outDie6(int column);

extern void initRand16(int randseed);	// init random # generator
extern int rand6(void); 				// declare external assembly function
extern double pow(double x, double y);

//-----------------------------------------------------------
//	global variables
volatile int WD_Cnt1;
volatile int WD_Delay;
volatile int notPushed;
volatile int waitCount;
volatile int randseed;
volatile int ledCounter;
volatile int ledOn;
volatile int direction;
volatile int currentLed;
volatile int waiting;
volatile int lastRoll1;
volatile int lastRoll2;
volatile int currentRoll1;
volatile int currentRoll2;
volatile int doubles;

volatile double highTone;
volatile double lowTone;
volatile double rasp;

int timeout = 5;


//-----------------------------------------------------------
//	main
void main(void)	{

	waitCount = 0;

	lastRoll1 = 1;
	lastRoll2 = 2;

	eZ430X_init(CALDCO_8MHZ);			// init board
	rasp = myCLOCK/130.813;				// C  (130.813 Hz)
	lowTone = myCLOCK/391.995;			// G  (391.995 Hz)
	highTone = myCLOCK/783.991;     	// G  (783.991 Hz)
	
	TBR &= 0x00;
	TBCTL=TBSSEL_2+ID_0+MC_1;
	TBCCTL2=OUTMOD_3;
	
     P4DIR|=0x20;       	     		//P4.5 output (buzzer)
     P4SEL|=0x20;						// P4.5 uses alternate function (TB2)
	
		
	lcd_init();							// init LCD

	// configure Watchdog
	WD_Cnt1 = WD_1SEC_CNT;				// set WD 1 second counter
	WDTCTL = WDT_CTL;					// Set Watchdog interval
	WD_Delay = 0;						// reset delay counter
	IE1 |= WDTIE;						// Enable WDT interrupt
	__bis_SR_register(GIE);				// enable interrupts


	lcd_backlight(1);					// turn on LCD
	notPushed = TRUE;

	while (1){
		flashLed();
		randomRollDice();
		compareRolls();
	}
}


int flashLed(void){
	lcd_display(LCD_2X_FONT | LCD_PROPORTIONAL);
	lcd_cursor(10, 2);					// position message
	printf("Roll the Dice!!!");
	__bis_SR_register(GIE);				// enable interrupts
	
	ledOn=FALSE;
	notPushed = TRUE;
	ledCounter =0;
	direction=currentLed=ledOn=1;
	
	P2IFG &= 0x00;
	P2IE |= 0x0f;						// turn on interrupts
	
	LPM0;
	
	notPushed = FALSE;
	
	P2IFG &= 0x00;
	P2IE |= 0x0f;						// turn on interrupts
	
	
	LED_1_OFF;							// turn off
	LED_2_OFF;							// turn off
	LED_3_OFF;							// turn off
	LED_4_OFF;							// turn off
	
	lcd_init();							// init LCD
	lcd_backlight(1);					// turn on LCD
	waitCount = 0;
	return 1;
}

int randomRollDice(void){
	int counter,pause;
	drawDieFrame(10);
	drawDieFrame(80);
	doubles = FALSE;
	for(counter=0,pause=1;counter<20;++counter){
		while(0x0f&(0x0f^P2IN)){
			rollDice();
			wait(5);
		}
		waitCount=0;
		rollDice();
		pause = pow(counter/5.0, 4);					// Get a pause value between 3 and 20
		wait(pause);									// wait for a progressively longer time
	}
	return 1;
}

int rollDice(void){
	writeDie1();									// write the first die to the screen
	writeDie2();									// write the second die to the screen
	signifyRoll();									// Do some stuff to say we rolled
	return 1;
}

int compareRolls(){
	if(currentRoll1==currentRoll2){
		doubles = TRUE;
	}
	if(lastRoll1==lastRoll2 && doubles){
		playTone(rasp, 20);
	}else if (doubles){
		playCharge();
	}else {
		playTone(highTone, 20);
	}
	lastRoll1 = currentRoll1;
	lastRoll2 = currentRoll2;
	doubles=FALSE;
	return 1;
}



int writeDie1(void){
	currentRoll1 = rand6();
//	currentRoll1 = 5;
	switch (currentRoll1){
		case 1: outDie1(DIE_ONE);break;
		case 2: outDie2(DIE_ONE);break;
		case 3: outDie3(DIE_ONE);break;
		case 4: outDie4(DIE_ONE);break;
		case 5: outDie5(DIE_ONE);break;
		case 6:	outDie6(DIE_ONE);break;
	}
	return 1;
}


int writeDie2(){
	currentRoll2 = rand6();
//	currentRoll2 = 5;
	switch (currentRoll2){
		case 1: outDie1(DIE_TWO);break;
		case 2: outDie2(DIE_TWO);break;
		case 3: outDie3(DIE_TWO);break;
		case 4: outDie4(DIE_TWO);break;
		case 5: outDie5(DIE_TWO);break;
		case 6: outDie6(DIE_TWO);break;
	}

	return 1;
}


int signifyRoll(void){
	lcd_backlight(0);
	playTone(lowTone, 4);
	lcd_backlight(1);
	return 1;
}

int playCharge(void){
	double G1 = myCLOCK/391.995;     // G  (391.995 Hz)
	double C1 = myCLOCK/523.251;     // C  (523.251 Hz)
	double E1 = myCLOCK/659.255;     // E  (659.255 Hz)
	double G2 = myCLOCK/783.991;     // G  (783.991 Hz)
	
	playTone(G1,4);
	playTone(C1,4);
	playTone(E1,4);
	playTone(G2,8);
	playTone(E1,4);
	playTone(G2,8);
	
	return 1;
}

int playTone(double frequency, int length){
	TBCCR2 = frequency/2;
	TBCCR0 = frequency;
	wait(length*5);
	TBCCR0 = 0;
	return 1;
}


/******************************************************************************
 *	Port 2 ISR														  		  *
 ******************************************************************************/
__interrupt void PORT2_ISR(void);
#pragma vector = PORT2_VECTOR
__interrupt void PORT2_ISR(void)
{
	P2IE &= ~0x0f;
	LPM0_EXIT;
}



/******************************************************************************
 *	Watchdog Timer ISR														  *
 ******************************************************************************/
__interrupt void WDT_ISR(void);
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
	ledCounter++;
	if (WD_Delay) WD_Delay--;			// decrement delay (if non-zero)

	if (--WD_Cnt1 == 0)
	{
		LED_GREEN_TOGGLE;					// Toggle Port P1.1
		waitCount++;
		WD_Cnt1 = WD_1SEC_CNT;			// reset counter
	}
	if (waitCount==timeout){
		lcd_backlight(0);					// turn on LCD
	}
	
	
	if(notPushed && ledOn && !waiting){
		waiting = TRUE;
		switch (currentLed){
		case 1:LED_1_ON; break;		// turn on
		case 2:LED_2_ON; break;		// turn on
		case 3:LED_3_ON; break;		// turn on
		case 4:LED_4_ON; break;		// turn on
		}
	}
	
	if(notPushed && ledOn && waiting){
		if(ledCounter == WD_1SEC_CNT/24){
			ledOn = FALSE;
		}
	}
	
	if(notPushed && !ledOn && waiting){
		waiting = FALSE;
		ledCounter = 0;
		LED_1_OFF;				// turn off
		LED_2_OFF;				// turn off
		LED_3_OFF;				// turn off
		LED_4_OFF;				// turn off
	}
	
	
	if(notPushed && !ledOn){
		ledOn = TRUE;
		randseed *= WD_Delay;
		currentLed += direction;
		if (currentLed==4||currentLed==1){
			direction = ~direction+1;
		}
	}
}
